﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ICSharpCode.WinFormsUI.Controls.Chart3D
{
    public class Camera
    {
        // 3D View
        float _theta = (float)(2 * Math.PI / 5.0);
        float _beta = (float)(2 * Math.PI / 9.0);

        Vertex _location = new Vertex(0, 0, 0);

        internal float Theta
        {
            get { return _theta; }
        }

        internal float Beta
        {
            get { return _beta; }
        }

        public Vertex Location
        {
            get { return _location; }
            set { _location = value; }
        }

        private Vertex Transform3D(Vertex p, float beta, float theta)
        {
            /*
             * | x |   | cos(beta) -sin(beta) 0 |   | cos(theta) 0 -sin(theta) |   | x0 |
             * | y | = | sin(beta)  cos(beta) 0 | * | 0          1  0          | * | y0 |
             * | z |   | 0          0         1 |   | sin(theta) 0  cos(theta) |   | z0 |
             */
            float x0 = p.X;
            float y0 = p.Y;
            float z0 = p.Z;

            float x1 = (float)(Math.Cos(beta) * x0 - Math.Sin(beta) * y0);
            float y1 = (float)(Math.Sin(beta) * x0 + Math.Cos(beta) * y0);
            float z1 = z0;

            float x2 = (float)(Math.Cos(theta) * x1 - Math.Sin(theta) * z1);
            float y2 = y1;
            float z2 = (float)(Math.Sin(theta) * x1 + Math.Cos(theta) * z1);

            float y3 = -x2; // fix ??
            float x3 = y2;
            float z3 = y3;

            return new Vertex(Location.X + x3, Location.Y - y3, z3);
        }

        public Point2D Transform2D(Vertex p)
        {
            Vertex pt = Transform3D(p, Beta, Theta);
            return new Point2D(pt.X, pt.Y);
        }

        public Point2D Transform2D(Point3D p)
        {
            Vertex pt = Transform3D(new Vertex(p.X, p.Z, p.Y), Beta, Theta);
            return new Point2D(pt.X, pt.Y);
        }

        public Point2D[] GetProjection(Vertex[] pts3d)
        {
            Point2D[] pts2d = new Point2D[pts3d.Length];
            for (int i = 0; i < pts3d.Length; i++)
            {
                pts2d[i] = Transform2D(pts3d[i]);
            }
            return pts2d;
        }

        public Point2D GetProjection(Vertex pts3d)
        {
            return Transform2D(pts3d);
        }

        public System.Drawing.PointF[] ToArrayPointF(Vertex[] pts3d)
        {
            System.Drawing.PointF[] pts2d = new System.Drawing.PointF[pts3d.Length];
            for (int i = 0; i < pts3d.Length; i++)
            {
                pts2d[i] = Transform2D(pts3d[i]).ToPointF();
            }
            return pts2d;
        }

        public void Rotate(float theta, float beta)
        {
            this._beta = beta;
            this._theta = theta;
        }

    }
}
